home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 426-450 / disk_434 / backup / backup.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  33KB  |  1,655 lines

  1.  
  2. /*
  3.  * BACKUP.C
  4.  *
  5.  * (C)Copyright 1986-90, Matthew Dillon, All Rights Reserved.
  6.  * Permission is granted to distribute for non-profit only.
  7.  *
  8.  *  Thanks to Jan Sven Trabandt for finding some major bugs!
  9.  *
  10.  * This program will backup a filesystem or directory, creating a single
  11.  * output file which can later be RESTORE'd from.  It is a quick way to
  12.  * backup your work to a 'backup' disk.
  13.  *
  14.  *  backup [options] path path path ... path [-ooutputfile]
  15.  *
  16.  *    NOTE:    if -o is not specified, not output file will be created
  17.  *
  18.  *    NOTE:    Any files/directories containing the keyword NOBACKUP in
  19.  *        its comment field will not be backed up.
  20.  *
  21.  *  options:
  22.  *
  23.  *    -0       (Restore): Cause all restored files to be placed
  24.  *             in the current (or -o) directory.  No directory
  25.  *             structure is restored at all
  26.  *
  27.  *    -A       ARCHIVE.  Clear the archive bit on backed up files
  28.  *
  29.  *    -U       UPDATE.     Backup only those files which have the archive bit
  30.  *           cleared.
  31.  *
  32.  *    -f[#KB]  Floppy... actually, this option is used to force the backup
  33.  *           program to automatically split up the backup files in #KB
  34.  *           sections (default 800).  I.E.  -f with nothing else will
  35.  *           use 800KB chunks.  -f200 would use 200KB chunks, etc...
  36.  *
  37.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  38.  *           AND RESTORE
  39.  *
  40.  *    -Fvol    example: -FDF0: -FDF1:  This command specifies the ordering
  41.  *           and number of (floppy) drives to backup to.  This allows
  42.  *           one to change floppies in one drive while it is backing up
  43.  *           to another.  It automatically cycles through the drives but
  44.  *           you still must specify an initial output file (-ofile) to
  45.  *           determine the base name for the files.
  46.  *
  47.  *           This command also forces user prompting.
  48.  *
  49.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  50.  *           AND RESTORE
  51.  *
  52.  *    -b       backup    (default if executable name is 'backup')
  53.  *
  54.  *    -r       restore    (default if executable nam is 'restore')
  55.  *
  56.  *    -a       append to the destination file.
  57.  *
  58.  *    -c       Compress files during backup
  59.  *
  60.  *    -Cpat    add file pattern to those which will not
  61.  *           be compressed.
  62.  *
  63.  *    -s       Only display directories as we go along.
  64.  *
  65.  *    -l/-t    (either option) Causes a RESTORE to only LIST the files,
  66.  *           not do an actual restore.
  67.  *
  68.  *    -T       (Restore) TIMESTAMP, COMMENT, AND PROTECTION BITS ONLY.
  69.  *           NO files are created.  It is assumed the files already
  70.  *           exist.  The timestamp and other fields are transfered
  71.  *           from the backup file to the already-restored files (useful
  72.  *           if the files were restored with a copy command that did
  73.  *           non copy the timestamps.  Even if the backup file is old,
  74.  *           you can recover most of your time data).
  75.  *
  76.  *    -S       Silent.    Don't display files or directories.
  77.  *
  78.  *    -nKB     Set buffer size to use, in KB.
  79.  *
  80.  *    -v       Verbose... Additionaly, display those files which will NOT
  81.  *           be backed up.
  82.  *
  83.  *    -pPAT    only file-paths matching this pattern are backed up.  You
  84.  *           may specify more than one '-p' option.
  85.  *
  86.  *    -dPAT    file-paths matching this pattern are NOT backed up.  you
  87.  *           may specify more than one '-d' option.
  88.  *
  89.  *    -ofile   Output File
  90.  *
  91.  *    -Ooffset Set Offset (manual recover on restore)
  92.  *
  93.  * ---------------------------------------------------------------------
  94.  *
  95.  * destination file format:
  96.  *
  97.  *  HDR = <HDR><N.B><datestamp>             -Backup Date
  98.  *  VOL = <VOL><name_size.B><name>            -VOLUME base
  99.  *  DDS = <DDS><name_size.B><name>            -down-directory
  100.  *  END = <END><0.B>                    -up directory
  101.  *  DAT = <DAT><N.B><datestamp>             -datestamp for file
  102.  *  PRO = <PRO><4.B><protection>            -protection for file
  103.  *  COM = <COM><N.B><comment>                -comment for file
  104.  *  FIL0= <FIL0><N.B><name><size.L><data>        -uncompressed file
  105.  *  FIL1= <FIL1><N.B><name><size.L><usize.L><data>  -compressed form #1
  106.  *  INC = <INC><12.B><ttlsize><strt><segsize>        -next file is part of an
  107.  *                             incomplete file
  108.  */
  109.  
  110. #include "defs.h"
  111. #include <libraries/dos.h>
  112. #include <libraries/dosextens.h>
  113.  
  114. ubyte    Break;
  115. ubyte    Restore;
  116. ubyte    NoStructure;
  117. ubyte    ListOnly;
  118. ubyte    ShowFiles = 1;
  119. ubyte    ShowDirs  = 1;
  120. ubyte    Verbose;
  121. ubyte    Archive;
  122. ubyte    Update;
  123. ubyte    Append;
  124. ubyte    Compress;
  125. ubyte    TimeStampOnly;
  126. char    *OutFile;
  127. long    BacBytes;
  128. short    BacCnt = 1;
  129. short    MyBreak;
  130.  
  131. char DirPath[256];
  132. short DPLen;
  133.  
  134. char    *BadFormat;
  135.  
  136. long    BufSize = 65536;
  137. long    BufI;
  138. ubyte    *Buf;
  139. long    InBufSize = 8192;
  140. long    InBufI, InBufN;
  141. ubyte    *InBuf;
  142. char    Overide;
  143.  
  144. MLIST    VList;        /*    Volume list (-F), of NODEs              */
  145. MLIST    DList;        /*    Directory Stack             */
  146.  
  147. MLIST    CSList;     /*    compression patterns            */
  148. MLIST    PSList;     /*    pick patterns                */
  149. MLIST    DSList;     /*    don't pick patterns                     */
  150.  
  151. long    CLen;        /*    Actual compressed file output length    */
  152. MLIST    CList;        /*    List of memory buffers            */
  153. SCOMP    *CWrite;    /*    Current memory buffer pointer        */
  154.  
  155. extern void *GetHead(MLIST *);
  156. extern void *GetTail(MLIST *);
  157. extern void *GetSucc(MNODE *);
  158. extern void *GetPred(MNODE *);
  159.  
  160. void    AddPattern  (MLIST *, char *);
  161. void    BackupFiles (int, char **);
  162. void    RestoreFiles(int, char **, long);
  163. FIB    *GetFileInfo(char *, long *);
  164. void    FreeFileInfo(FIB *, long);
  165. void    PushDir     (char *, long);
  166. int    PopDirs     (uword);
  167. void    BackupFlagHasFile(void);
  168. long    scan_directory(FIB *, long);
  169. int    mycheckbreak(void);
  170. long    scan_file   (FIB *, long);
  171. int    match_file  (char *);
  172. void    writeheaders(FIB *);
  173. int    newfile     (void);
  174. int    read_file   (short, char *, long, long);
  175. int    openoutput  (char *, int, int);
  176. void    oputc        (char);
  177. void    outlwatseek (long, long);
  178. void    owrite        (void *, long);
  179. void    dumpoutput  (void);
  180. void    dumpcrc     (void);
  181. void    closeoutput (void);
  182. long    outbytes    (void);
  183. void    outentry    (ubyte, int, void *);
  184. int    openinput   (char *, long);
  185. void    closeinput  (void);
  186. void    seekinputend(void);
  187. void    setinputbound(long);
  188. long    oread        (void *, long);
  189. void    AppendCrc   (ubyte *, long);
  190. int    oreadchar   (void);
  191. void    rollbackinput(void);
  192. void    mputc        (char);
  193. void    mwrite        (char *, long);
  194. SCOMP    *NewSComp   (void);
  195. void    transfer0   (long);
  196. void    transfer1   (void);
  197.  
  198. int    brk        (void);
  199. void    UnCompressFile(long);
  200. long    CompressFile(char *, long);
  201.  
  202.  
  203. int
  204. brk()
  205. {
  206.     MyBreak = 1;
  207.     return(0);
  208. }
  209.  
  210. main(ac, av)
  211. char **av;
  212. {
  213.     register short i, notdone;
  214.     register char  *str;
  215.     long manOffset = 0;
  216.     short xac = 0;
  217.     static char *Xav[256];
  218.  
  219.     BadFormat = "Bad Format";
  220.     SetSignal(0, SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D);
  221.     onbreak(brk);
  222.  
  223.     NewList(&VList);
  224.     NewList(&DList);
  225.     NewList(&CList);
  226.  
  227.     NewList(&PSList);
  228.     NewList(&DSList);
  229.     NewList(&CSList);
  230.  
  231.     AddPattern(&CSList, "*.Z");
  232.     AddPattern(&CSList, "*.ARC");
  233.     AddPattern(&CSList, "*.ZOO");
  234.     AddPattern(&CSList, "*.LZH");
  235.  
  236.     for (str = av[0] + strlen(av[0]); str >= av[0] && *str != '/' && *str != ':'; --str);
  237.     ++str;
  238.     if ((*str|0x20) == 'r')
  239.     Restore = 1;
  240.  
  241.     if (ac == 1) {
  242.     printf("Backup/Restore V2.06, (c)Copyright 1988,1989 Matthew Dillon, All Rights Reserved\n", str);
  243.     printf("Backup/Restore is useful for HD backup and file transfers\n");
  244.     printf("%s -rbactlvASTU -d<pat> -p<pat> -f[#kb] -F<vol> -n<#kb> -ofile <file-dir-list>\n", str);
  245.     puts("\nread the docs for more info.  Example for use w/ file transfer:");
  246.     puts("\t1> backup -c file/dir -oout.bak     -create archive");
  247.     puts("\t1> restore -t out.bak               -list archive");
  248.     puts("\t1> restore out.bak [-odest]         -restore archive");
  249.     }
  250.  
  251.     for (i = 1; i < ac; ++i) {
  252.     str = av[i];
  253.     if (*str != '-') {
  254.         if (xac == sizeof(Xav)/sizeof(Xav[0])) {
  255.         printf("Maximum %d files/dirs specifiable on command line\n", sizeof(Xav)/sizeof(Xav[0]));
  256.         exit(15);
  257.         }
  258.         Xav[xac++] = str;
  259.         continue;
  260.     }
  261.     notdone = 1;
  262.     ++str;
  263.  
  264.     while (notdone && *str) {
  265.         switch(*str) {
  266.         case '0':
  267.         NoStructure = 1;
  268.         break;
  269.         case 'r':
  270.         Restore = 1;
  271.         break;
  272.         case 'b':
  273.         Restore = 0;
  274.         break;
  275.         case 'a':
  276.         Append = 1;
  277.         break;
  278.         case 'c':
  279.         Compress = 1;
  280.         break;
  281.         case 'd':
  282.         AddPattern(&DSList, str + 1);
  283.         notdone = 0;
  284.         break;
  285.         case 'f':
  286.         BacBytes = 800 * 1024;
  287.         if (str[1] >= '0' && str[1] <= '9') {
  288.             BacBytes = atoi(str+1) * 1024;
  289.             notdone = 0;
  290.         }
  291.         break;
  292.         case 'F':
  293.         {                    /*    strlen(str+1)+1 */
  294.             char *name = (str[1]) ? str + 1 : av[++i];
  295.             NODE *node = malloc(sizeof(NODE) + strlen(name) + 1);
  296.             node->ln_Name = (char *)(node + 1);
  297.             strcpy((char *)(node + 1), name);
  298.             AddTail(&VList, node);
  299.         }
  300.         notdone = 0;
  301.         break;
  302.         case 'O':
  303.         {
  304.             char *name = (str[1]) ? str + 1 : av[++i];
  305.             manOffset = atoi(name);
  306.         }
  307.         Overide = 1;
  308.         notdone = 0;
  309.         break;
  310.         case 'n':
  311.         {
  312.             char *name = (str[1]) ? str + 1 : av[++i];
  313.             BufSize = atoi(name) * 1024;
  314.         }
  315.         if (BufSize <= 0)
  316.             BufSize = 65536;
  317.         notdone = 0;
  318.         break;
  319.         case 'o':
  320.         {
  321.             char *name = (str[1]) ? str + 1 : av[++i];
  322.             OutFile = name;
  323.         }
  324.         notdone = 0;
  325.         break;
  326.         case 'p':
  327.         {
  328.             char *name = (str[1]) ? str + 1 : av[++i];
  329.             AddPattern(&PSList, name);
  330.         }
  331.         notdone = 0;
  332.         break;
  333.         case 's':
  334.         ShowFiles = 0;
  335.         break;
  336.         case 't':
  337.         case 'l':
  338.         ListOnly = 1;
  339.         break;
  340.         case 'v':
  341.         Verbose= 1;
  342.         break;
  343.         case 'A':
  344.         Archive= 1;
  345.         break;
  346.         case 'C':
  347.         {
  348.             char *name = (str[1]) ? str + 1 : av[++i];
  349.             AddPattern(&CSList, name);
  350.         }
  351.         notdone = 0;
  352.         break;
  353.         case 'S':
  354.         ShowFiles = 0;
  355.         ShowDirs  = 0;
  356.         break;
  357.         case 'T':
  358.         TimeStampOnly = 1;
  359.         break;
  360.         case 'U':
  361.         Update = 1;
  362.         break;
  363.         default:
  364.         puts("failure, backup w/ no args for help");
  365.         exit(20);
  366.         }
  367.         ++str;
  368.     }
  369.     }
  370.     if (i > ac) {
  371.     puts("Expected argument to last option!");
  372.     exit(20);
  373.     }
  374.     Buf = malloc(BufSize);
  375.     if (Buf == NULL) {
  376.     printf("Unable to malloc %ld bytes\n", BufSize);
  377.     exit(20);
  378.     }
  379.     if (ListOnly)
  380.     InBufSize = 512;    /*  small buffer to avoid read overhead */
  381.                 /*  since we are skipping the meat    */
  382.  
  383.     InBuf = malloc(InBufSize);
  384.     if (InBuf == NULL) {
  385.     printf("Unable to malloc %ld bytes\n", InBufSize);
  386.     exit(20);
  387.     }
  388.  
  389.     if (Restore)
  390.     RestoreFiles(xac, Xav, manOffset);
  391.     else
  392.     BackupFiles(xac, Xav);
  393.     return(0);
  394. }
  395.  
  396. void
  397. AddPattern(list, str)
  398. MLIST *list;
  399. char *str;
  400. {
  401.     register NODE *node = malloc(sizeof(NODE));
  402.  
  403.     AddTail(list, node);
  404.     node->ln_Name = str;
  405. }
  406.  
  407.  
  408. long SaveLock;
  409.  
  410. void
  411. BackupFiles(ac, av)
  412. char **av;
  413. {
  414.     register short i;
  415.     register char *str, *ptr;
  416.     char notdone;
  417.  
  418.     if (OutFile && openoutput(OutFile, Append, ((BacBytes)?1:0)) == 0)
  419.     exit(20);
  420.     if (OutFile) {      /*  write header    */
  421.     DATESTAMP Date;
  422.     DateStamp(&Date);
  423.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  424.     }
  425.  
  426.     SaveLock = CurrentDir(DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  427.  
  428.     for (i = 0; i < ac; ++i) {
  429.     str = av[i];
  430.  
  431.     /*
  432.      *  Push DDS entries for each name segment of the path
  433.      */
  434.  
  435.     notdone = 1;
  436.     while (notdone) {
  437.         for (ptr = str; *ptr && *ptr != ':' && *ptr != '/'; ++ptr);
  438.         switch(*ptr) {
  439.         case '/':   /*  normal directory    */
  440.         *ptr = 0;
  441.         PushDir(str, XDDS);
  442.         str = ptr + 1;
  443.         *ptr = '/';
  444.         break;
  445.         case ':':   /*  volume              */
  446.         *ptr = 0;
  447.         PushDir(str, XVOL);
  448.         str = ptr + 1;
  449.         *ptr = ':';
  450.         break;
  451.         default:    /*  directory or file    */
  452.         {
  453.             char *path = av[i];
  454.             FIB *fib;
  455.             long lock;
  456.  
  457.             if (fib = GetFileInfo(path, &lock)) {
  458.             if (fib->fib_DirEntryType > 0) {
  459.                 if (str[0])
  460.                 PushDir(str, XDDS);
  461.                 lock = scan_directory(fib, lock);
  462.                 if (str[0])
  463.                 PopDirs(1);
  464.             } else {
  465.                 lock = scan_file(fib, lock);
  466.             }
  467.             FreeFileInfo(fib, lock);
  468.             } else {
  469.             printf("Unable to get info for %s\n", av[i]);
  470.             }
  471.         }
  472.         notdone = 0;
  473.         break;
  474.         }
  475.     }
  476.     PopDirs((uword)-1);
  477.     }
  478.  
  479.     UnLock(CurrentDir(SaveLock));
  480.     if (OutFile)
  481.     closeoutput();
  482. }
  483.  
  484. DATESTAMP Date;
  485. ulong Crc;        /*  compare w/    */
  486. ulong CrcGen;
  487. ulong CrcSeek;        /*  (backup) where in file is CrcGen lw?    */
  488. char CrcEna;
  489. char Comment[256];
  490. char Scr[256];
  491. long Protection;
  492. long IncSize;        /*  Size of entire file     */
  493. long IncSeek;        /*  Seek offset into file   */
  494. long IncLen;        /*  # bytes in this segment */
  495.  
  496. void
  497. RestoreFiles(ac, av, startoffset)
  498. char **av;
  499. long startoffset;
  500. {
  501.     register short i;
  502.     register char *str;
  503.     char notdone;
  504.     char havedate;
  505.     char havecrc;
  506.     char havepro;
  507.     char havecom;
  508.     char haveinc;
  509.     long bytes;
  510.     long actual;
  511.     long baselock;
  512.     long lock;
  513.     PROC *proc = (PROC *)FindTask(NULL);
  514.  
  515.     if (OutFile) {
  516.     lock = Lock(OutFile, SHARED_LOCK);
  517.     if (lock == NULL && (lock = CreateDir(OutFile))) {
  518.         UnLock(lock);
  519.         lock = Lock(OutFile, SHARED_LOCK);
  520.     }
  521.     } else {
  522.     lock = Lock("", SHARED_LOCK);
  523.     }
  524.     if (!lock) {
  525.     printf("Unable to lock/create %s\n", (OutFile) ? OutFile : "<currentdir>");
  526.     return;
  527.     }
  528.     baselock = lock;
  529.     SaveLock = CurrentDir(DupLock(baselock));
  530.  
  531.     for (i = 0; i < ac; ++i) {
  532.     str = av[i];
  533.  
  534.     lock = CurrentDir(SaveLock);
  535.     if (openinput(str, startoffset) == 0) {
  536.         startoffset = 0;
  537.         printf("Unable to open %s for input\n", str);
  538.         CurrentDir(lock);
  539.         continue;
  540.     }
  541.     startoffset = 0;
  542.     CurrentDir(lock);
  543.  
  544.     lock = DupLock(baselock);
  545.     UnLock(CurrentDir(lock));
  546.  
  547.     notdone = 1;
  548.     havedate = havecrc = havepro = havecom = haveinc = 0;
  549.  
  550.     while (notdone) {
  551.         short c = oreadchar();
  552.         short l = oreadchar();
  553. recover:
  554.         switch(c) {
  555.         case -1:        /*  EOF */
  556.         notdone = 0;
  557.         break;
  558.         case 0:        /*  NUL */
  559.         case 'z'&0x1F:      /*  ^Z  */
  560.         if (Overide == 0)
  561.             notdone = 0;
  562.         break;
  563.         case XVOL:
  564.         case XDDS:
  565.         oread(Scr, l);
  566.         Scr[l] = 0;
  567.  
  568.         /*
  569.          *  In the replacement of the first
  570.          *  argument case, we are already in
  571.          *  the proper directory.
  572.          */
  573.  
  574.         if (EMPTYLIST(DList) && OutFile) {
  575.             register short j = strlen(OutFile);
  576.  
  577.             UnLock(CurrentDir(DupLock(SaveLock)));
  578.             c = XDDS;
  579.             strcpy(Scr, OutFile);
  580.             if (j--) {
  581.             if (OutFile[j] == ':') {
  582.                 Scr[j] = 0;
  583.                 c = XVOL;
  584.             }
  585.             if (OutFile[j] == '/')
  586.                 Scr[j] = 0;
  587.             }
  588.         }
  589.         PushDir(Scr, c);
  590.         if (ShowDirs)
  591.             printf("%-40s\n", DirPath);
  592.         if (ListOnly)
  593.             break;
  594.         if (NoStructure == 0) {
  595.             if (c == XVOL) {
  596.             lock = Lock(DirPath, SHARED_LOCK);  /*  DirPath incs ':'    */
  597.             } else {
  598.             lock = Lock(Scr, SHARED_LOCK);
  599.             if (lock == NULL && (lock = CreateDir(Scr))) {
  600.                 UnLock(lock);
  601.                 lock = Lock(Scr, SHARED_LOCK);
  602.             }
  603.             }
  604.         }
  605.         {
  606.             SDIR *sd = GetTail(&DList);
  607.             sd->HaveFile = 1;            /*    don't remove dir    */
  608.         }
  609.         if (NoStructure == 0) {
  610.             if (lock == NULL) {
  611.             printf("Unable to create directory %s\n", Scr);
  612.             notdone = 0;
  613.             } else {
  614.             UnLock(CurrentDir(lock));
  615.             }
  616.         }
  617.         break;
  618.         case XEND:
  619.         {
  620.             SDIR *sd = GetTail(&DList);
  621.             ubyte type;
  622.  
  623.             c = 1;
  624.             if (!sd)
  625.             break;
  626.             type = sd->Type;
  627.             strcpy(Scr, sd->Element);
  628.             c = PopDirs(1);
  629.             if (ListOnly)
  630.             break;
  631.             if (type == XVOL)   /*  no parent directory */
  632.             break;
  633.             if (NoStructure == 0) {
  634.             lock = ParentDir(proc->pr_CurrentDir);
  635.             if (lock == NULL) {
  636.                 puts("Unable to ParentDir!");
  637.                 notdone = 0;
  638.             } else {
  639.                 UnLock(CurrentDir(lock));
  640.                 /*
  641.                 if (c == 0)
  642.                 DeleteFile(Scr);
  643.                 */
  644.             }
  645.             }
  646.         }
  647.         break;
  648.         case XCRC:
  649.         if (l != 4) {
  650.             puts(BadFormat);
  651.             notdone = SkipBad(&c, &l);
  652.             goto recover;
  653.         }
  654.         oread(&Crc, l);
  655.         havecrc = 1;
  656.         break;
  657.         case XDAT:
  658.         if (l != sizeof(DATESTAMP)) {
  659.             puts(BadFormat);
  660.             notdone = SkipBad(&c, &l);
  661.             goto recover;
  662.         }
  663.         oread(&Date, l);
  664.         havedate = 1;
  665.         break;
  666.         case XPRO:
  667.         if (l != 4) {
  668.             puts("Expected 4 bytes for protection");
  669.             notdone = SkipBad(&c, &l);
  670.             goto recover;
  671.         }
  672.         oread(&Protection, l);
  673.         havepro = 1;
  674.         break;
  675.         case XCOM:
  676.         oread(Comment, l);
  677.         Comment[l] = 0;
  678.         havecom = 1;
  679.         break;
  680.         case XFIL0:
  681.         case XFIL1:
  682.         if (!havepro)
  683.             Protection = 0;
  684.         if (!havecom)
  685.             Comment[0] = 0;
  686.         if (!havedate)
  687.             DateStamp(&Date);
  688.         if (!haveinc)
  689.             IncSize = 0;
  690.  
  691.         oread(Scr, l);
  692.         Scr[l] = 0;
  693.         oread(&bytes, 4);       /*  length of file  */
  694.         actual = bytes;
  695.         if (c == XFIL1) {
  696.             oread(&actual, 4);
  697.             bytes -= 4;
  698.         }
  699.         setinputbound(bytes);
  700.         {
  701.             short res = read_file(c, Scr, bytes, actual);
  702.             seekinputend();
  703.             if (res < 0)
  704.             goto bend;
  705.         }
  706.         if (ListOnly)
  707.             goto bend;
  708.         if (Archive)
  709.             SetProtection(Scr, Protection|FIBF_ARCHIVE);
  710.         else
  711.             SetProtection(Scr, Protection&~FIBF_ARCHIVE);
  712.         if (havecrc && Crc != CrcGen)
  713.             printf("WARNING, Crc failed! %s\n", Scr);
  714.         if (havedate)
  715.             setfiledate(Scr, &Date);
  716.         if (havecom && Comment[0])
  717.             SetComment(Scr, Comment);
  718. bend:
  719.         havecom = havecrc = havedate = havepro = haveinc = 0;
  720.         break;
  721.         case XHDR:
  722.         if (l != sizeof(DATESTAMP)) {
  723.             puts("expected sizeof datestamp");
  724.             notdone = SkipBad(&c, &l);
  725.             goto recover;
  726.         }
  727.         oread(&Date, l);
  728.         printf(" ----- BACKUP ----- BACKUP DATE: %s\n", datetos(&Date, Scr, NULL));
  729.         break;
  730.         case XINC:
  731.         if (l != 12) {
  732.             puts("expected 12 bytes for XINC");
  733.             notdone = SkipBad(&c, &l);
  734.             goto recover;
  735.         }
  736.         oread(&IncSize, 4);
  737.         oread(&IncSeek, 4);
  738.         oread(&IncLen,  4);
  739.         haveinc = 1;
  740.         break;
  741.         default:
  742.         printf("Unknown Record Type: %02x\n", c);
  743.         notdone = SkipBad(&c, &l);
  744.         goto recover;
  745.         }
  746.         setinputbound(-1);
  747.         if (mycheckbreak()) {
  748.         Break = 1;
  749.         notdone = 0;
  750.         break;
  751.         }
  752.     }
  753.     if (Break)
  754.         break;
  755.     }
  756.     UnLock(baselock);
  757.     UnLock(CurrentDir(SaveLock));
  758. }
  759.  
  760. SkipBad(pc, pl)
  761. short *pc;
  762. short *pl;
  763. {
  764.     long skip = 0;
  765.     long offset = otellread();
  766.     short notdone = 1;
  767.     short c;
  768.     short l;
  769.  
  770. loop:
  771.     while ((c = oreadchar()) >= 0 && c != XDAT)
  772.     ++skip;
  773.     if (c == XDAT) {
  774.     l = oreadchar();
  775.     ++skip;
  776.     if (l != sizeof(DATESTAMP))
  777.         goto loop;
  778.     }
  779.     printf("Error at offset %d, skipping %d bytes", offset, skip);
  780.     if (c < 0) {
  781.     printf(" (EOF reached!)");
  782.     notdone = 0;
  783.     }
  784.     printf("\n");
  785.     *pc = c;
  786.     *pl = l;
  787.     return((int)notdone);
  788. }
  789.  
  790. FIB *
  791. GetFileInfo(path, plock)
  792. char *path;
  793. long *plock;
  794. {
  795.     register long lock;
  796.     register FIB *fib;
  797.  
  798.     *plock = NULL;
  799.     if (lock = Lock(path, SHARED_LOCK)) {
  800.     if (fib = malloc(sizeof(FIB))) {
  801.         if (Examine(lock, fib)) {
  802.         *plock = lock;
  803.         return(fib);
  804.         }
  805.         free(fib);
  806.     }
  807.     UnLock(lock);
  808.     }
  809.     return(NULL);
  810. }
  811.  
  812. void
  813. FreeFileInfo(fib, lock)
  814. FIB *fib;
  815. long lock;
  816. {
  817.     if (fib)
  818.     free(fib);
  819.     if (lock)
  820.     UnLock(lock);
  821. }
  822.  
  823. void
  824. PushDir(element, type)
  825. char *element;
  826. {
  827.     register SDIR *sd = malloc(sizeof(SDIR));
  828.     register char *str = malloc(strlen(element)+1);
  829.  
  830.     strcpy(str, element);
  831.     sd->Type = type;
  832.     sd->HaveFile = 0;
  833.     sd->Element = str;
  834.     AddTail(&DList, sd);
  835.     strcat(DirPath+DPLen, str);
  836.     if (type == XVOL)
  837.     strcat(DirPath+DPLen, ":");
  838.     else if (type == XDDS)
  839.     strcat(DirPath+DPLen, "/");
  840.     DPLen += strlen(DirPath+DPLen);
  841. }
  842.  
  843. int
  844. PopDirs(num)
  845. uword num;
  846. {
  847.     register SDIR *sd, *sp;
  848.     char lasthave = 0;
  849.  
  850.     while (num && (sd = GetTail(&DList))) {
  851.     lasthave |= sd->HaveFile;
  852.     if (!Restore && sd->HaveFile)       /*  MUST write end-block    */
  853.         outentry(XEND, 0, NULL);
  854.     if (sp = GetPred(sd))
  855.         sp->HaveFile |= sd->HaveFile;
  856.     Remove(sd);
  857.     DPLen -= strlen(sd->Element) + 1;
  858.     if (DPLen < 0) {
  859.         puts("DPLEN ERROR");
  860.         DPLen = 0;
  861.     }
  862.     DirPath[DPLen] = 0;
  863.     free(sd->Element);
  864.     free(sd);
  865.     --num;
  866.     }
  867.     return((int)lasthave);
  868. }
  869.  
  870. void
  871. BackupFlagHasFile()
  872. {
  873.     register SDIR *sd;
  874.     SDIR *sdb = NULL;
  875.  
  876.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  877.     if (sd->HaveFile == 0)
  878.         sdb = sd;
  879.     }
  880.     for (sd = sdb; sd; sd = GetSucc(sd)) {
  881.     sd->HaveFile = 1;
  882.     outentry(sd->Type, strlen(sd->Element), sd->Element);
  883.     }
  884. }
  885.  
  886.  
  887. /*
  888.  *  SCAN_DIRECTORY()        (CORE OF BACKUP)
  889.  */
  890.  
  891. long
  892. scan_directory(dirfib, dirlock)
  893. FIB *dirfib;
  894. long dirlock;
  895. {
  896.     register FIB *fib;
  897.     long lock;
  898.     long save = CurrentDir(dirlock);
  899.  
  900.     if (Update == 0)        /* force save entire tree */
  901.     BackupFlagHasFile();
  902.     while (ExNext(dirlock, dirfib) && (fib = GetFileInfo(dirfib->fib_FileName, &lock))) {
  903.     if (fib->fib_DirEntryType > 0) {
  904.         PushDir(fib->fib_FileName, XDDS);
  905.         if (ShowDirs)
  906.         printf("%-40s (DIR)\n", DirPath);
  907.         if (NoBack(fib) == 0)
  908.         lock = scan_directory(fib, lock);
  909.         PopDirs(1);
  910.     } else {
  911.         if (NoBack(fib) == 0)
  912.         lock = scan_file(fib, lock);
  913.     }
  914.     FreeFileInfo(fib, lock);
  915.     if (Break || mycheckbreak()) {
  916.         Break = 1;
  917.         break;
  918.     }
  919.     }
  920.     CurrentDir(save);
  921.     return(dirlock);
  922. }
  923.  
  924. int
  925. mycheckbreak()
  926. {
  927.  
  928.     if (MyBreak || (SetSignal(0, (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D))) {
  929.     puts(" ***** BREAK *****");
  930.     return(1);
  931.     }
  932.     return(0);
  933. }
  934.  
  935. /*
  936.  *  SCAN_FILE()
  937.  *
  938.  *  If the file is accepted, write out pending directory entries, do
  939.  *  compression if any, and write out the file.
  940.  */
  941.  
  942. long
  943. scan_file(fib, lock)
  944. FIB *fib;
  945. long lock;
  946. {
  947.     long save;
  948.     char dbuf[32];
  949.  
  950.     strcat(DirPath, fib->fib_FileName);
  951.  
  952.     if (Update && (fib->fib_Protection & FIBF_ARCHIVE))
  953.     goto nomatch;
  954.     if (!match_file(DirPath))
  955.     goto nomatch;
  956.  
  957.     if (ShowFiles)
  958.     printf("%-40s %6ld %s\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  959.  
  960.     BackupFlagHasFile();
  961.     if (OutFile) {
  962.     save = CurrentDir(lock);
  963.     if (openinput("", 0) == 0) {
  964.         CurrentDir(save);
  965.         printf("Unable to open %s\n", fib->fib_FileName);
  966.         goto nomatch;
  967.     }
  968.     if (Compress && CompressFile(fib->fib_FileName, fib->fib_Size)) {
  969.         if (OutFile && BacBytes && outbytes() + CLen > BacBytes) {
  970.         if (newfile() == 0)
  971.             goto skip1;
  972.         }
  973.         writeheaders(fib);
  974.         outentry(XFIL1, strlen(fib->fib_FileName), fib->fib_FileName);
  975.         CLen += 4;
  976.         owrite(&CLen, 4);
  977.         CLen -= 4;
  978.         owrite(&fib->fib_Size, 4);
  979.         transfer1();
  980.     } else {
  981.         if (OutFile && BacBytes && outbytes() + fib->fib_Size > BacBytes) {
  982.         if (newfile() == 0)
  983.             goto skip1;
  984.         }
  985.         if (Compress)
  986.         rollbackinput();
  987.         writeheaders(fib);
  988.         outentry(XFIL0, strlen(fib->fib_FileName), fib->fib_FileName);
  989.         owrite(&fib->fib_Size, 4);
  990.         transfer0(fib->fib_Size);
  991.     }
  992.     outlwatseek(CrcSeek, CrcGen);
  993. skip1:
  994.     closeinput();
  995.     CurrentDir(save);
  996.     }
  997.     if (Break)
  998.     goto nomatch;
  999.     if (Archive && !(fib->fib_Protection & FIBF_ARCHIVE)) {
  1000.     if (save = ParentDir(lock)) {
  1001.         UnLock(lock);
  1002.         save = CurrentDir(save);
  1003.         SetProtection(fib->fib_FileName, fib->fib_Protection | FIBF_ARCHIVE);
  1004.         lock = CurrentDir(save);
  1005.     }
  1006.     }
  1007.     DirPath[DPLen] = 0;
  1008.     return(lock);
  1009. nomatch:
  1010.     if (Verbose)
  1011.     printf("%-40s (NOT ACCEPTED)\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  1012.  
  1013.     DirPath[DPLen] = 0;
  1014.     return(lock);
  1015. }
  1016.  
  1017. int
  1018. match_file(name)
  1019. char *name;
  1020. {
  1021.     register NODE *node;
  1022.  
  1023.     for (node = (NODE *)PSList.mlh_Head; node->ln_Succ; node = node->ln_Succ) {
  1024.     if (WildCmp(node->ln_Name, name))
  1025.         break;
  1026.     }
  1027.     if (node->ln_Succ == NULL && !EMPTYLIST(PSList))
  1028.     return(0);
  1029.  
  1030.     for (node = (NODE *)DSList.mlh_Head; node->ln_Succ; node = node->ln_Succ) {
  1031.     if (WildCmp(node->ln_Name, name))
  1032.         return(0);
  1033.     }
  1034.     return(1);
  1035. }
  1036.  
  1037. void
  1038. writeheaders(fib)
  1039. register FIB *fib;
  1040. {
  1041.     long dummy = 0;
  1042.     outentry(XDAT, sizeof(DATESTAMP), &fib->fib_Date);
  1043.     outentry(XPRO, 4, &fib->fib_Protection);
  1044.     if (fib->fib_Comment[0])
  1045.     outentry(XCOM, strlen(fib->fib_Comment), fib->fib_Comment);
  1046.     outentry(XCRC, 4, &dummy);
  1047.     CrcSeek = outbytes() - 4;
  1048. }
  1049.  
  1050. /*
  1051.  *  (1) Write out XEND's to finish this archive,
  1052.  *  (2) Open a new output file
  1053.  *  (3) Write out XDDS's to build back to the current position
  1054.  */
  1055.  
  1056. int
  1057. newfile()
  1058. {
  1059.     {
  1060.     register SDIR *sd;
  1061.  
  1062.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  1063.         if (sd->HaveFile)
  1064.         outentry(XEND, 0, NULL);
  1065.     }
  1066.     }
  1067.     ++BacCnt;
  1068.     if (OutFile && openoutput(OutFile, Append, 1) == 0) {
  1069.     Break = 1;
  1070.     return(0);
  1071.     }
  1072.     {
  1073.     register SDIR *sd;
  1074.     DATESTAMP Date;
  1075.     DateStamp(&Date);
  1076.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  1077.     for (sd = GetHead(&DList); sd; sd = GetSucc(sd)) {
  1078.         if (sd->HaveFile)
  1079.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  1080.     }
  1081.     }
  1082.     return(1);
  1083. }
  1084.  
  1085. int
  1086. read_file(type, fname, inbytes, outbytes)
  1087. short type;
  1088. char *fname;
  1089. long inbytes;
  1090. long outbytes;
  1091. {
  1092.     char dbuf[32];
  1093.     long save;
  1094.  
  1095.     strcat(DirPath, fname);
  1096.  
  1097.     if (!match_file(DirPath)) {
  1098.     if (Verbose)
  1099.         printf("%-40s (NOT ACCEPTED)\n", DirPath);
  1100.     goto nomatch;
  1101.     }
  1102.  
  1103.     if (ShowFiles)
  1104.     printf("%-40s %6ld %6ld %s %s\n", DirPath, inbytes, outbytes, datetos(&Date, dbuf, NULL), Comment);
  1105.  
  1106.     if (ListOnly)
  1107.     goto nomatch;
  1108.     if (TimeStampOnly)
  1109.     goto matchskip;
  1110.  
  1111.     openoutput(fname, 0, 0);
  1112.     switch(type) {
  1113.     case XFIL0:
  1114.     transfer0(inbytes);
  1115.     break;
  1116.     case XFIL1:
  1117.     CrcGen = 0;
  1118.     CrcEna = 1;
  1119.     UnCompressFile(inbytes);
  1120.     CrcEna = 0;
  1121.     save = CrcGen;
  1122.     transfer1();                /*  ??? needed ??? */
  1123.     CrcGen = save;
  1124.     break;
  1125.     }
  1126.     closeoutput();
  1127. matchskip:
  1128.     DirPath[DPLen] = 0;
  1129.     return(1);
  1130. nomatch:
  1131.     DirPath[DPLen] = 0;
  1132.     return(-1);
  1133. }
  1134.  
  1135. /*
  1136.  *  FILE SUPPORT
  1137.  */
  1138.  
  1139. static int Infd = -1;
  1140. static int Outfd = -1;
  1141. static long OutBytes;
  1142.  
  1143. int
  1144. openoutput(name, append, enabtail)
  1145. char *name;
  1146. {
  1147.     char *ptr = name;
  1148.     static NODE *VNode;     /*    Volume node */
  1149.     long lock;
  1150.     extern int errno;
  1151.  
  1152.     if (Outfd >= 0) {
  1153.     dumpoutput();
  1154.     close(Outfd);
  1155.     Outfd = -1;
  1156.     }
  1157.     if (enabtail) {
  1158.     if (VNode)
  1159.         VNode = GetSucc(VNode);
  1160.     if (!VNode)
  1161.         VNode = GetHead(&VList);
  1162.     if (VNode) {
  1163.         ptr = malloc(strlen(VNode->ln_Name)+strlen(name)+8);
  1164.         sprintf(ptr, "%s%s.%02ld", VNode->ln_Name, name, BacCnt);
  1165.     } else {
  1166.         ptr = malloc(strlen(name)+8);
  1167.         sprintf(ptr, "%s.%02ld", name, BacCnt);
  1168.     }
  1169.     }
  1170.     OutBytes = 0;
  1171.     while (GetHead(&VList)) {
  1172.     short c;
  1173.     short d;
  1174.  
  1175.     fprintf(stderr, "Ready for %s (y=go,n=abort) -", ptr);
  1176.     fflush(stderr);
  1177.     if ((c = getc(stdin)) == EOF) {
  1178.         fprintf(stderr, "EOF, aborted\n");
  1179.         c = 'n';
  1180.     }
  1181.     while ((d = getc(stdin)) != EOF && d != '\n');
  1182.     if ((c|0x20) == 'y')
  1183.         break;
  1184.     if ((c|0x20) == 'n')
  1185.         goto skip;
  1186.     }
  1187.     if (enabtail && SaveLock)                 /*  original directory  */
  1188.     lock = CurrentDir(SaveLock);
  1189.     if (append) {
  1190.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_APPEND);
  1191.     if (Outfd >= 0) {
  1192.         OutBytes = lseek(Outfd, 0L, 2);
  1193.         /* lseek(Outfd, 0L, 0); */
  1194.     }
  1195.     } else {
  1196.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_TRUNC);
  1197.     }
  1198.     if (enabtail && SaveLock)                 /*  back to before      */
  1199.     CurrentDir(lock);
  1200.     if (Outfd < 0)
  1201.     printf("Unable to open output file %s (%ld)\n", ptr, errno);
  1202. skip:
  1203.     BufI = 0;
  1204.     if (enabtail)
  1205.     free(ptr);
  1206.     return(Outfd >= 0);
  1207. }
  1208.  
  1209. void
  1210. oputc(v)
  1211. char v;
  1212. {
  1213.     ++OutBytes;
  1214.     if (Outfd >= 0) {
  1215.     if (BufI == BufSize)
  1216.         dumpoutput();
  1217.     Buf[BufI++] = v;
  1218.     }
  1219. }
  1220.  
  1221. void
  1222. outlwatseek(pos, lw)
  1223. long pos;
  1224. long lw;
  1225. {
  1226.     long index = BufI + pos - OutBytes; /*  index into buffer    */
  1227.  
  1228.     if (index > BufI - 4) {
  1229.     puts("SW ERROR");
  1230.     return;
  1231.     }
  1232.     if (index >= 0) {
  1233.     Buf[index+0] = lw >> 24;
  1234.     Buf[index+1] = lw >> 16;
  1235.     Buf[index+2] = lw >> 8;
  1236.     Buf[index+3] = lw;
  1237.     } else {                /*  uh oh   */
  1238.     if (Outfd >= 0) {
  1239.         long old = lseek(Outfd, 0, 1);  /*  save current pos */
  1240.         lseek(Outfd, pos, 0);           /*  seek back        */
  1241.         write(Outfd, (char *)&lw, 4);   /*  write data       */
  1242.         lseek(Outfd, old, 0);           /*  seek to end      */
  1243.     }
  1244.     }
  1245. }
  1246.  
  1247. void
  1248. owrite(buf, n)
  1249. void *buf;
  1250. long n;
  1251. {
  1252.     register long avail;
  1253.  
  1254.     OutBytes += n;
  1255.     if (Outfd >= 0) {
  1256.     while (BufI + n > BufSize) {
  1257.         avail = BufSize - BufI;
  1258.         movmem(buf, Buf + BufI, avail);
  1259.         n  -= avail;
  1260.         buf = (void *)((char *)buf + avail);
  1261.         BufI = BufSize;
  1262.         dumpoutput();
  1263.     }
  1264.     movmem(buf, Buf + BufI, n);
  1265.     BufI += n;
  1266.     }
  1267. }
  1268.  
  1269. void
  1270. dumpoutput()
  1271. {
  1272.     if (Outfd >= 0 && BufI) {
  1273.     write(Outfd, Buf, BufI);
  1274.     BufI = 0;
  1275.     }
  1276. }
  1277.  
  1278. void
  1279. closeoutput()
  1280. {
  1281.     if (Outfd >= 0) {
  1282.     dumpoutput();
  1283.     close(Outfd);
  1284.     Outfd = -1;
  1285.     }
  1286. }
  1287.  
  1288. long
  1289. outbytes()
  1290. {
  1291.     return(OutBytes);
  1292. }
  1293.  
  1294. /*
  1295.  *  <type><len><buf>
  1296.  */
  1297.  
  1298. void
  1299. outentry(type, len, buf)
  1300. ubyte type;
  1301. int len;
  1302. void *buf;
  1303. {
  1304.     OutBytes += len + 2;
  1305.     if (Outfd >= 0) {
  1306.     if (BufI + len + 2 >= BufSize)
  1307.         dumpoutput();
  1308.     Buf[BufI+0] = type;
  1309.     Buf[BufI+1] = len;
  1310.     movmem(buf, Buf+BufI+2, len);
  1311.     BufI += len + 2;
  1312.     }
  1313. }
  1314.  
  1315. ulong OMax;
  1316.  
  1317. int
  1318. openinput(name, offset)
  1319. char *name;
  1320. long offset;
  1321. {
  1322.     if (Infd >= 0)
  1323.     close(Infd);
  1324.     Infd = open(name, O_RDONLY);
  1325.     InBufI = InBufN = 0;
  1326.     OMax = -1;
  1327.     if (Infd >= 0 && offset)
  1328.     lseek(Infd, offset, 0);
  1329.     return(Infd >= 0);
  1330. }
  1331.  
  1332. void
  1333. closeinput()
  1334. {
  1335.     if (Infd >= 0)
  1336.     close(Infd);
  1337.     Infd = -1;
  1338. }
  1339.  
  1340. void
  1341. seekinputend()
  1342. {
  1343.     register long inbuf   = InBufI - InBufN;
  1344.     register long forward = OMax;
  1345.  
  1346.     if (forward > inbuf) {
  1347.     lseek(Infd, forward - inbuf, 1);
  1348.     OMax = InBufI = InBufN = 0;
  1349.     return;
  1350.     }
  1351.     InBufN += forward;
  1352. }
  1353.  
  1354. void
  1355. setinputbound(max)
  1356. long max;
  1357. {
  1358.     OMax = max;
  1359. }
  1360.  
  1361. long
  1362. oread(buf, n)
  1363. void *buf;
  1364. long n;
  1365. {
  1366.     long x = 0;
  1367.     long avail;
  1368.  
  1369.     if (Infd < 0)
  1370.     return(0);
  1371.     if (n > OMax)
  1372.     n = OMax;
  1373.  
  1374.     while (n > (avail = InBufI - InBufN)) {
  1375.     if (InBufN == -1)
  1376.         return(0);
  1377.     movmem(InBuf + InBufN, buf, avail);
  1378.     AppendCrc(buf, avail);
  1379.     OMax-= avail;
  1380.     n   -= avail;
  1381.     buf = (void *)((char *)buf + avail);
  1382.     x   += avail;
  1383.     InBufI = read(Infd, InBuf, InBufSize);
  1384.     InBufN = 0;
  1385.     if (InBufI <= 0) {
  1386.         InBufI = 0;
  1387.         return(x);
  1388.     }
  1389.     }
  1390.     movmem(InBuf + InBufN, buf, n);
  1391.     AppendCrc(buf, n);
  1392.     InBufN += n;
  1393.     x += n;
  1394.     OMax -= n;
  1395.     return(x);
  1396. }
  1397.  
  1398. long
  1399. otellread()
  1400. {
  1401.     long pos = 0;
  1402.     if (Infd >= 0)
  1403.     pos = lseek(Infd, 0L, 1) - (InBufI - InBufN);
  1404.     return(pos);
  1405. }
  1406.  
  1407. int
  1408. oreadchar()
  1409. {
  1410.     if (!OMax || Infd < 0)
  1411.     return(-1);
  1412.     if (InBufN == InBufI) {
  1413.     if (InBufN < 0)
  1414.         return(EOF);
  1415.     InBufI = read(Infd, InBuf, InBufSize);
  1416.     InBufN = 0;
  1417.     if (InBufI == 0) {
  1418.         InBufN = InBufI = -1;
  1419.         return(-1);
  1420.     }
  1421.     }
  1422.     if (CrcEna)
  1423.     CrcGen = (CrcGen << 3) ^ InBuf[InBufN] ^ (CrcGen >> 29);
  1424.     return((int)InBuf[InBufN++]);
  1425. }
  1426.  
  1427. void
  1428. AppendCrc(buf, bytes)
  1429. register ubyte *buf;
  1430. register long bytes;
  1431. {
  1432.     if (CrcEna) {
  1433.     while (bytes--)
  1434.         CrcGen = (CrcGen << 3) ^ *buf++ ^ (CrcGen >> 29);
  1435.     }
  1436. }
  1437.  
  1438. void
  1439. rollbackinput()
  1440. {
  1441.     if (Infd >= 0)
  1442.     lseek(Infd, 0L, 0);
  1443.     InBufI = InBufN = 0;
  1444. }
  1445.  
  1446. void
  1447. mputc(v)
  1448. char v;
  1449. {
  1450.     register SCOMP *sc = CWrite;
  1451.  
  1452.     ++CLen;
  1453.     if (sc->N == sc->Bytes) {
  1454.     sc = GetSucc(sc);
  1455.     if (sc == NULL);
  1456.         sc = NewSComp();
  1457.     if (sc == NULL) {
  1458.         puts("SCOMP FAILED");
  1459.         return;
  1460.     }
  1461.     sc->N = 0;
  1462.     CWrite = sc;
  1463.     }
  1464.     ((char *)(sc + 1))[sc->N++] = v;
  1465. }
  1466.  
  1467. void
  1468. mwrite(buf, n)
  1469. char *buf;
  1470. long n;
  1471. {
  1472.     register SCOMP *sc = CWrite;
  1473.     register long avail;
  1474.  
  1475.     CLen += n;
  1476.     while ((avail = sc->Bytes - sc->N) < n) {
  1477.     movmem(buf, (char *)(sc + 1) + sc->N, avail);
  1478.     buf += avail;
  1479.     n -= avail;
  1480.     sc->N = sc->Bytes;
  1481.     sc = GetSucc(sc);
  1482.     if (sc == NULL)
  1483.         sc = NewSComp();
  1484.     if (sc == NULL) {
  1485.         puts("SCOMP FAILED");
  1486.         return;
  1487.     }
  1488.     sc->N = 0;
  1489.     }
  1490.     movmem(buf, (char *)(sc + 1) + sc->N, n);
  1491.     sc->N += n;
  1492.     CWrite = sc;
  1493. }
  1494.  
  1495. SCOMP *
  1496. NewSComp()
  1497. {
  1498.     register SCOMP *sc = malloc(sizeof(SCOMP) + 8192);
  1499.  
  1500.     if (sc) {
  1501.     sc->Bytes = 8192;
  1502.     sc->N = 0;
  1503.     AddTail(&CList, sc);
  1504.     }
  1505.     return(sc);
  1506. }
  1507.  
  1508. void
  1509. transfer0(n)
  1510. long n;
  1511. {
  1512.     register long len;
  1513.  
  1514.     if (Outfd < 0)
  1515.     return;
  1516.  
  1517.     CrcGen = 0;
  1518.     CrcEna = 1;
  1519.     for (len = BufSize - BufI; n; len = BufSize - BufI) {
  1520.     if (len == 0) {
  1521.         dumpoutput();
  1522.         len = BufSize;
  1523.     }
  1524.     if (n < len)
  1525.         len = n;
  1526.     oread(Buf + BufI, len);
  1527.     BufI += len;
  1528.     n -= len;
  1529.     OutBytes += len;
  1530.     }
  1531.     CrcEna = 0;
  1532. }
  1533.  
  1534. /*
  1535.  *  Compression Routines
  1536.  *
  1537.  *  transfer1()    : Backup:   copy compression buffer to output file
  1538.  */
  1539.  
  1540. void
  1541. transfer1()
  1542. {
  1543.     register long len;
  1544.     register SCOMP *sc = GetHead(&CList);
  1545.     register ubyte *ptr;
  1546.     long n = CLen;
  1547.  
  1548.     if (Outfd < 0)
  1549.     return;
  1550.     CrcGen = 0;
  1551.     CrcEna = 1;
  1552.     for (sc = GetHead(&CList); sc && n; sc = GetSucc(sc)) {
  1553.     len = sc->Bytes;
  1554.     ptr = (ubyte *)(sc + 1);
  1555.     if (n < len)
  1556.         len = n;
  1557.     n -= len;
  1558.  
  1559.     AppendCrc(ptr, len);
  1560.  
  1561.     while (len > BufSize - BufI) {
  1562.         movmem(ptr, Buf + BufI, BufSize - BufI);
  1563.         ptr += BufSize - BufI;
  1564.         len -= BufSize - BufI;
  1565.         OutBytes += BufSize - BufI;
  1566.         BufI = BufSize;
  1567.         dumpoutput();
  1568.     }
  1569.     movmem(ptr, Buf + BufI, len);
  1570.     BufI += len;
  1571.     OutBytes += len;
  1572.     }
  1573.     CrcEna = 0;
  1574.     if (n)
  1575.     puts("Unexpected EOF in compression file");
  1576. }
  1577.  
  1578. /*
  1579.  *  NoBack() returns true if 'NOBACK' is found in the fib_Comment
  1580.  *  field.
  1581.  */
  1582.  
  1583. NoBack(fib)
  1584. FIB *fib;
  1585. {
  1586.     char *str = fib->fib_Comment;
  1587.  
  1588.     while (*str) {
  1589.     if (*str == 'N' && strncmp(str, "NOBACK", 6) == 0)
  1590.         return(1);
  1591.     ++str;
  1592.     }
  1593.     return(0);
  1594. }
  1595.  
  1596. /*
  1597.  *  quick hack to fix some macro bugs...
  1598.  */
  1599.  
  1600. long
  1601. CTOB(cptr)
  1602. void *cptr;
  1603. {
  1604.     return((long)cptr >> 2);
  1605. }
  1606.  
  1607. void *
  1608. BTOC(bptr)
  1609. long bptr;
  1610. {
  1611.     return((void *)(bptr << 2));
  1612. }
  1613.  
  1614. void *
  1615. GetHead(list)
  1616. MLIST *list;
  1617. {
  1618.     MNODE *node = list->mlh_Head;
  1619.     if (node->mln_Succ)
  1620.     return(node);
  1621.     return(NULL);
  1622. }
  1623.  
  1624. void *
  1625. GetTail(list)
  1626. MLIST *list;
  1627. {
  1628.     MNODE *node = list->mlh_TailPred;
  1629.     if (node->mln_Pred)
  1630.     return(node);
  1631.     return(NULL);
  1632. }
  1633.  
  1634. void *
  1635. GetSucc(node)
  1636. MNODE *node;
  1637. {
  1638.     node = node->mln_Succ;
  1639.     if (node->mln_Succ)
  1640.     return(node);
  1641.     return(NULL);
  1642. }
  1643.  
  1644. void *
  1645. GetPred(node)
  1646. MNODE *node;
  1647. {
  1648.     node = node->mln_Pred;
  1649.     if (node->mln_Pred)
  1650.     return(node);
  1651.     return(NULL);
  1652. }
  1653.  
  1654.  
  1655.